package com.google.code.virtualhockey.vhx.server.servlet.rest

import scala.collection.mutable.HashMap
import com.google.code.virtualhockey.vhx.server.servlet.rest.error.RestNoCommandHandlerException

/**
 * Utility to look up command handlers
 */
trait RestCommandHandlerLookup {
  private[this] val _mapCmdCache: HashMap[String,RestCommandHandler] = HashMap.empty

  /**
   * Finds and returns the handler that matches the given command.
   */
  final def getHandler( cmd: RestCommandRequest ): RestCommandHandler = {
    val strKey = getCacheKey( cmd )
    var optHandler = getFromCache( strKey ).asInstanceOf[Option[RestCommandHandler]]
    if ( optHandler == None ) {
      optHandler = lookupHandler( cmd ).asInstanceOf[Option[RestCommandHandler]]
      if ( optHandler == None )
        throw new RestNoCommandHandlerException( cmd.command )
      else 
        _mapCmdCache += ( strKey -> optHandler.get )
    }
    optHandler.get
  }

  /**
   * <p>
   * Returns the key that should be used to cache already looked up handlers. By
   * default the command's name is used as cache key.
   * </p>
   *
   * <p>
   * Please override if you need more control over command handler caching.
   * </p>
   *
   * @param cmd the command for which to obtain a cache key
   * @return the key used for command caching
   */
  protected def getCacheKey( cmd: RestCommandRequest ): String = cmd.command

  /**
   * Tries to load the command handler from the command handler cache using the
   * given key.
   *
   * @param strKey the cache key
   * @return the found command handler or <code>None</code>
   */
  protected def getFromCache( strKey: String ): Option[RestCommandHandler] = _mapCmdCache.get( strKey )

  /**
   * Looks up the {@link RestCommandHandler} that matches the given command. Please
   * do not use any caching mechanism in the method's implementation as this
   * method is only called if no command handler had already been found in the
   * handler cache.
   *
   * @param cmd the command for which to get a handler
   * @return the found handler or <code>None</code> to indicate that no handler
   *         was found
   */
  protected def lookupHandler( cmd: RestCommandRequest ): Option[RestCommandHandler]
}
